#ifndef SCT_RTSPCLIENT_RTSPCLIENT_H
#define SCT_RTSPCLIENT_RTSPCLIENT_H

#include <UsageEnvironment.hh>
#include <BasicUsageEnvironment.hh>
#include <GroupsockHelper.hh>
#include <liveMedia.hh>
#include <liveMedia_version.hh>

#include "sct/core/common.h"
#include "sct/core/mutex.h"

#include "sct/rtspclient/rtspclientinterface.h"

namespace sct
{
class CRTSPClient;

class CMyRTSPClient: public RTSPClient
{
	friend class CRTSPClient;
public:
	CMyRTSPClient(CRTSPClient * owner, UsageEnvironment& env, char const* rtspURL,
		       int verbosityLevel = 0,
		       char const* applicationName = NULL,
		       portNumBits tunnelOverHTTPPortNum = 0,
		       int socketNumToServer = -1):
		    	   RTSPClient(env, rtspURL, verbosityLevel, applicationName,
		                   tunnelOverHTTPPortNum, socketNumToServer){mOwner = owner;}

private:
	CRTSPClient * mOwner;
};

class CRTSPClient: public CRTSPClientInterface
{
public:
	class CAVParam
	{
	public:
		int profile;
		int frequency;
		int channel_config;
	};

public:
	CRTSPClient();
	virtual ~CRTSPClient();

	virtual int demux();
	virtual void reset();
	virtual void setMaxDelay(const int64_t delay);///<microsecond
	virtual void setServerUrl(const char * url);

protected:
	class CTrack
	{
	public:
		MediaSubsession * sub;

		uint8_t * buffer;
		int sz_buffer;

		CRTSPClient * owner;
		CAVParam av_param;
	};

protected:
	void pushH264Data(const int64_t & pts, uint8_t*d, const uint32_t & len, const uint32_t & dropFramePre);
	void pushAACData(CRTSPClient::CTrack* track,
			const int64_t & pts, uint8_t*d, const uint32_t & len, const uint32_t & dropFramePre);
	void pushAMRData(const int64_t & pts, uint8_t*d, const uint32_t & len, const uint32_t & dropFramePre);
	void pushTsData(const int64_t & pts, uint8_t*d, const uint32_t & len, const uint32_t & dropFramePre);

private:
	void _setMaxDelay(const int64_t delay);///<microsecond
	void _reset();
	void start();

	bool wait_Live555_response(int i_timeout = 0);

	void setSDP(const std::string & sdp);
	BasicTaskScheduler * scheduler();
	CMyRTSPClient * liveClient();
	int intervalKeepAlive()const;
	MediaSession * mediaSession();

	void checkIfNeedReset();

	void parseAACParam(const char* sdp, CAVParam * param);
private:
	static void continueAfterOPTIONS(
			RTSPClient* client,
			int result_code,
			char* result_string );

	static void continueAfterGetParameter(
			RTSPClient* client,
			int result_code,
			char* result_string );

	static void continueAfterDESCRIBE( RTSPClient* client, int result_code,
            char* result_string );

	static void TaskInterruptRTSP( void *p_private );

	static void TaskKeepAlive( void *p_private );

	static void StreamRead( void *p_private, unsigned int i_size,
	                        unsigned int i_truncated_bytes, struct timeval pts,
	                        unsigned int duration );

	static void StreamClose( void *p_private );
	static void TaskInterruptData( void *p_private );

	static void default_live555_callback( RTSPClient* client, int result_code, char* result_string );

private:
	enum State
	{
		S_Init = SCT_ENUM_OFFSET,
		S_Terminate,
		S_Play,
	};

private:
	BasicTaskScheduler * mSched;
	BasicUsageEnvironment* mEnv;
	CMyRTSPClient * mMyClient;
	std::string mSdp;
	MediaSession * mMs;
	std::list<CTrack*> mTracks;
	int mState;

	int mMaxTimeOutLimit;//millisecond not microsecond
	int mIntervalKeepAlive;//millisecond

	char mEventFlag;
	bool mErr;
	int mRetCode;

	int mKeepAlive;
	TaskToken mTaskKeepAlive;
	int mNeedReset;

	double mLastGetDataTime;
	double mMaxGapTime;

	int64_t mMaxDelay;///<microsecond

	CMutex * mObjMutex;

	std::string mServerUrl;
	std::string mTargetServerUrl;
};

}

#endif
